/* $ZEL: sis1100_dma_startstop.c,v 1.2 2005/02/11 21:52:38 wuestner Exp $ */

/*
 * Copyright (c) 2005
 * 	Peter Wuestner.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions, and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include "sis1100_sc.h"

int
sis1100_dma_start(struct sis1100_softc *sc)
{
#if 0
    u_int32_t dmamode;

    SEM_LOCK(sc->demand_dma.sem);
    /* is an other process using dma? */
    if ((sc->demand_dma.status!=dma_invalid)&&(sc->demand_dma.owner!=current)){
        SEM_UNLOCK(sc->demand_dma.sem);        
        return EBUSY;
    }
    if (sc->demand_dma.status==dma_running) {
        SEM_UNLOCK(sc->demand_dma.sem);        
        return EBUSY;
    }
    if (sc->demand_dma.status!=dma_ready) {
        SEM_UNLOCK(sc->demand_dma.sem);        
        return ENOTTY;
    }

    /* prepare PLX */
    dmamode=3     /* bus width 32 bit */
        |(1<<6)   /* enabe TA#/READY# input */
        |(1<<7)   /* enable BTERM# input */
        |(1<<8)   /* enable loacal burst */
        |(1<<9)   /* scatter/gather mode */
        |(1<<10)  /* enabe "done interrupt" */
        |(1<<11)  /* local address is constant */
        |(1<<12)  /* demand mode */
        |(1<<14)  /* enable DMA EOT# */
        |(1<<15)  /* fast terminate mode */
        |(1<<17); /* routing DMA interrupt to PCI bus */
    plxwritereg( sc, DMACSR0_DMACSR1, 1<<3 ); /* clear irq */
    plxwritereg( sc, DMAMODE0, dmamode );
    plxwritereg(sc, DMADPR0, sc->demand_dma.desc_pages[0].dma_handle|1);

    /* enable dma irq in plx chip */
    sc->got_irqs=0;
    sis1100_enable_irq(sc, plxirq_dma0, 0);

    /* clear byte counter */
    /* does not exist
    sis1100writereg(sc, byte_counter, 0 );
    mb();
    */

    /* enable and start dma transfer */
    pDEBUG(sc, "dma_start: Start DMA transfer");
    plxwritereg(sc, DMACSR0_DMACSR1, 3);

    sc->demand_dma.status=dma_running;
    SEM_UNLOCK(sc->demand_dma.sem);        
#endif
    return 0;
}

int
sis1100_dma_stop(struct sis1100_softc *sc, size_t* bytes)
{
#if 0
    SEM_LOCK(sc->demand_dma.sem);
    /* is an other process using dma? */
    if ((sc->demand_dma.status!=dma_invalid)&&(sc->demand_dma.owner!=current)){
        SEM_UNLOCK(sc->demand_dma.sem);        
        return EBUSY;
    }
    if (sc->demand_dma.status!=dma_running) {
        SEM_UNLOCK(sc->demand_dma.sem);        
        return ENOTTY;
    }

    sis1100_disable_irq(sc, plxirq_dma0, 0);

    if (!(plxreadreg(sc, DMACSR0_DMACSR1)&0x10)) {
        int c=0;
        sis1100writereg(sc, sr, sr_abort_dma);
        while (!(plxreadreg(sc, DMACSR0_DMACSR1)&0x10) && (c++<1000000)) {}
        if (!(plxreadreg(sc, DMACSR0_DMACSR1)&0x10)) {
	    pERROR(sc, "dma_stop: DMA NOT STOPED");
            SEM_UNLOCK(sc->demand_dma.sem);        
	    return EIO;
        }
    }
    /*
    {
        size_t _bytes;
        _bytes=sis1100readreg(sc, byte_counter);
        pINFO(sc, "dma_stop: byte_count=%u", _bytes);
        if (bytes)
            *bytes=_bytes;
    }
    */

    sc->demand_dma.status=dma_ready;
    SEM_UNLOCK(sc->demand_dma.sem);        
#endif
    return 0;
}

int
sis1100_dma_wait(struct sis1100_softc *sc, size_t* bytes)
{
#if 0
    int res;

    SEM_LOCK(sc->demand_dma.sem);
    /* is an other process using dma? */
    if ((sc->demand_dma.status!=dma_invalid)&&(sc->demand_dma.owner!=current)){
        SEM_UNLOCK(sc->demand_dma.sem);        
        return EBUSY;
    }
    if (sc->demand_dma.status!=dma_running) {
        SEM_UNLOCK(sc->demand_dma.sem);        
        return ENOTTY;
    }

    sc->got_irqs=0;

    if ((plxreadreg(sc, DMACSR0_DMACSR1)&0x10)) {
        goto finished;
    }

    res=wait_event_interruptible (
        sc->local_wait,
        (sc->got_irqs & got_dma0)
    );
    if (res) {
        SEM_UNLOCK(sc->demand_dma.sem);        
        return EINTR;
    }

finished:

    sis1100_disable_irq(sc, plxirq_dma0, 0);

    /*
    {
        size_t _bytes;
        _bytes=sis1100readreg(sc, byte_counter);
        pDEBUG(sc, "dma_wait: byte_count=%u", _bytes);
        if (bytes)
            *bytes=_bytes;
    }
    */

    sc->demand_dma.status=dma_ready;
    SEM_UNLOCK(sc->demand_dma.sem);        
#endif
    return 0;
}
